home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume6 / ditrev < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  11.0 KB

  1. Subject: v06i042:  Page reverser for ditroff (ditrev)
  2. Newsgroups: mod.sources
  3. Approved: rs@mirror.UUCP
  4.  
  5. Submitted by: cca!caip!uw-beaver!uw-wally!schwartz (Michael F. Schwartz)
  6. Mod.sources: Volume 6, Issue 42
  7. Archive-name: ditrev
  8.  
  9. Documents generated by ditroff(1) come out with page 1 on the bottom and the
  10. last page on top when you print them.  I got tired of having to manually
  11. reverse the pages, so I hacked up a filter that reverses the pages for you.
  12. It's simple to use, and runs pretty fast:
  13.  
  14.     ditrev [file]
  15.  
  16. outputs to stdout an image like the input, except all the pages are reversed.
  17. So, to use this, use something like the following command:
  18.  
  19.        troff inputfile -t | ditrev | lpr -n
  20.  
  21. (where the /usr/local/ditroff is before the /bin/troff version in your search
  22. path).
  23.  
  24. Note: There is another program called psrev that reverses PostScript file pages
  25. (my filter reverses ditroff pages; ditroff output is translated to PostScript
  26. before being printed on laserwriters).  More about the differences between
  27. these programs is described in the man page.
  28.  
  29.  - Mike Schwartz
  30.    University of Washington Computer Science Department
  31.    ihnp4!uw-beaver!schwartz  (USENET)
  32.    schwartz@wally.arpa  (ARPANET)
  33.    schwartz%wally.arpa@csnet-relay.arpa  (CSNET)
  34.  
  35. #! /bin/sh
  36. # This is a shell archive, meaning:
  37. # 1. Remove everything above the #! /bin/sh line.
  38. # 2. Save the resulting text in a file.
  39. # 3. Execute the file with /bin/sh (not csh) to create:
  40. #    ditrev.1
  41. #    ditrev.c
  42. #    makefile
  43. # This archive created: Fri Jun 27 15:47:59 1986
  44. export PATH; PATH=/bin:/usr/bin:$PATH
  45. echo shar: "extracting 'ditrev.1'" '(2762 characters)'
  46. if test -f 'ditrev.1'
  47. then
  48.     echo shar: "will not over-write existing file 'ditrev.1'"
  49. else
  50. sed 's/^    X//' << \SHAR_EOF > 'ditrev.1'
  51.     X.TH DITREV 1 local
  52.     X.SH NAME
  53.     Xditrev \- reverse ditroff(1) pages
  54.     X.SH SYNOPSIS
  55.     X.B ditrev
  56.     X[file]
  57.     X.SH DESCRIPTION
  58.     X.I Ditrev
  59.     Xreverses the pages in a ditroff
  60.     Xfile (or stdin, if no file is
  61.     Xspecified) and outputs to stdout. This is useful when sending typeset
  62.     Xditroff output to a laser printer:
  63.     Xditroff outputs the pages in an order that, without this filter, forces
  64.     Xyou to manually reverse them all.
  65.     X.PP
  66.     XTo use this filter, you would use something like the following command:
  67.     X.RS
  68.     Xtroff file -t -Pps | ditrev | lpr -n -Pps
  69.     X.RE
  70.     X(where /usr/local/ditroff is ahead of /usr/bin in your search path).
  71.     X.SH COMPARISON WITH PSREV
  72.     XThere is another program called psrev
  73.     Xthat reverses the pages of PostScript
  74.     Xfiles.  Since many laser printers (e.g., the MacIntosh LaserWriter) use
  75.     XPostScript, one could do
  76.     X.RS
  77.     Xtroff file -t -Pps | dps | psrev | lpr -Pps
  78.     X.RE
  79.     X(dps translates between ditroff format and PostScript).  Although I didn't know
  80.     Xof the existence of psrev when I wrote
  81.     X.I ditrev,
  82.     Xit turns out that there are several advantages of
  83.     X.I ditrev
  84.     Xover psrev:
  85.     X.IP 1.
  86.     X.I Ditrev
  87.     Xis more general - it works no matter what image format the printer accepts.
  88.     XThus,
  89.     X.I ditrev
  90.     Xcan be used for any printer, and the user doesn't have to know what format
  91.     Xthe printer expects.  
  92.     X.IP
  93.     XOn the other hand, psrev works no matter what
  94.     Xtext formatter generated the file, as long as the printer accepts
  95.     XPostScript.  But, since most text processors (Scribe and tex(1L) in
  96.     Xparticular) output the pages in the correct order, this probably
  97.     Xisn't too useful.
  98.     X.IP 2.
  99.     X.I Ditrev
  100.     Xruns faster than psrev.
  101.     X.IP 3.
  102.     XNeither dps nor psrev seem to have man pages.
  103.     X.IP 4.
  104.     XDps is often only available on the machine
  105.     Xwhich drives the printer, so you would actually have to do
  106.     X.RS
  107.     X.RS
  108.     Xtroff file -t -Pps | rsh 'dps | psrev | lpr -Pps'
  109.     X.RE
  110.     XThis can become more complicated and installation dependent
  111.     Xif these other filters aren't
  112.     Xin your search path on the remote machine.
  113.     X.RE
  114.     X.SH AUTHOR
  115.     XMike Schwartz, University of Washington Computer Science Department.
  116.     X.ce 3
  117.     Xihnp4!uw-beaver!schwartz  (USENET)
  118.     Xschwartz@wally.arpa  (ARPANET)
  119.     Xschwartz%wally.arpa@csnet-relay.arpa  (CSNET)
  120.     X.SH BUGS
  121.     X.IP 1.
  122.     XThe transformation performed is very simple; I discovered it by looking at the
  123.     Xoutput of ditroff and the source of dsun(1).  Thus, although this filter
  124.     Xseems to work, I may have made some oversimplifications.
  125.     X.IP 2.
  126.     XInput is read into dynamically allocated buffers, and hence, for a large input
  127.     Xfile, alot of memory is used (but no more than necessary, if compiled with
  128.     X-DREALLOC).  This could have been avoided by disallowing input from stdin and
  129.     Xusing fseek(3) to move through the file. I didn't do this because I wanted to
  130.     Xallow input to come from stdin.
  131.     X.SH SEE ALSO
  132.     Xtroff(1), ditroff(1), dsun(1), lpr(1), tex(1L), printcap(5).
  133. SHAR_EOF
  134. if test 2762 -ne "`wc -c < 'ditrev.1'`"
  135. then
  136.     echo shar: "error transmitting 'ditrev.1'" '(should have been 2762 characters)'
  137. fi
  138. fi
  139. echo shar: "extracting 'ditrev.c'" '(5198 characters)'
  140. if test -f 'ditrev.c'
  141. then
  142.     echo shar: "will not over-write existing file 'ditrev.c'"
  143. else
  144. sed 's/^    X//' << \SHAR_EOF > 'ditrev.c'
  145.     X/* Program to reverse pages from input and print on stdout, for ditroff(1)
  146.     X * input.  This is useful when sending typeset ditroff output to a laser
  147.     X * printer:  ditroff outputs the pages in an order that, without this filter,
  148.     X * forces you to manually reverse them all.
  149.     X *
  150.     X * The transformation is simple: Below is some sample input. The X's below
  151.     X * represent any character other than "p"; "p" delimits pages, and "x trailer"
  152.     X * delimits the end of the last page.  Also, all lines start in column 1.
  153.     X *    Xstartingstuff
  154.     X *    p1
  155.     X *    Xpage1stuff
  156.     X *    p2
  157.     X *    Xpage2stuff
  158.     X *    x trailer
  159.     X *    Xfinalstuff
  160.     X *
  161.     X * This input, when run through this filter, will produce the following output:
  162.     X *    Xstartingstuff
  163.     X *    p2
  164.     X *    Xpage2stuff
  165.     X *    p1
  166.     X *    Xpage1stuff
  167.     X *    x trailer
  168.     X *    Xfinalstuff
  169.     X *
  170.     X * By Mike Schwartz, 6-24-86.
  171.     X *    ihnp4!uw-beaver!schwartz  (USENET)
  172.     X *    schwartz@wally.arpa  (ARPANET)
  173.     X *    schwartz%wally.arpa@csnet-relay.arpa  (CSNET)
  174.     X */
  175.     X
  176.     X
  177.     X#include <stdio.h>
  178.     X
  179.     X#define PAGEBUFSIZE 30000    /* Number of bytes initially allocated for each
  180.     X                postscript page.  I empirically determined that
  181.     X                this is plenty more than ever seems to be
  182.     X                needed (max was about 18k).  If compiled with
  183.     X                -DREALLOC, there is no waste involved, since
  184.     X                the buffers are realloc'd after their size is
  185.     X                determined.  There seems to be similar time and
  186.     X                CPU usage characteristics with or without
  187.     X                -DREALLOC, but the space used is considerably
  188.     X                less with -DREALLOC: a 320k input file caused
  189.     X                the dynamic size to grow to about 500k with
  190.     X                -DREALLOC, and to about 1200k without it.  */
  191.     X
  192.     X#define MAXPAGES 500         /* Max number of pages in the document */
  193.     X
  194.     X#define PageDelim(Char) (Char == 'p')
  195.     X#define EndOfAllPagesDelimString "x trailer"
  196.     X#define EndOfAllPages(Line) (strncmp(Line, EndOfAllPagesDelimString, 9) == 0)
  197.     X
  198.     Xint PageIndex = 0;
  199.     X
  200.     Xmain(argc, argv)
  201.     Xint argc;
  202.     Xchar **argv;
  203.     X{
  204.     X    FILE *InputFile = stdin;
  205.     X    char *InputBufPtr;
  206.     X    int CharIndex = 0;
  207.     X    char *PageBuf[MAXPAGES];
  208.     X    char *fgets(), *malloc(), *realloc();
  209.     X
  210.     X    if (argc > 2) {
  211.     X        fputs("Usage: ditrev [file]\n", stderr);
  212.     X        exit(1);
  213.     X    }
  214.     X
  215.     X    if (argc == 2) {
  216.     X        InputFile = fopen(argv[1], "r");
  217.     X        if (InputFile == NULL) {
  218.     X            perror("ditrev: fopen");
  219.     X            exit(1);
  220.     X        }
  221.     X    }
  222.     X
  223.     X    PageBuf[PageIndex] = malloc(PAGEBUFSIZE);
  224.     X    if (PageBuf[PageIndex] == NULL)
  225.     X        Abort("malloc returned no storage");
  226.     X
  227.     X    /* Copy preliminary stuff (before first page) from input to output */
  228.     X    do {
  229.     X        InputBufPtr = fgets(&PageBuf[PageIndex][CharIndex],
  230.     X                    PAGEBUFSIZE, InputFile);
  231.     X        if (InputBufPtr == NULL)  /* EOF */
  232.     X            Abort("Invalid input format");
  233.     X        if (PageDelim(*InputBufPtr))
  234.     X            break;
  235.     X        fputs(InputBufPtr, stdout);
  236.     X    } while(1);
  237.     X
  238.     X
  239.     X    /* Now read and store away all pages until hit EndOfAllPages */
  240.     X    do {
  241.     X        InputBufPtr = fgets(&PageBuf[PageIndex][CharIndex],
  242.     X                    PAGEBUFSIZE, InputFile);
  243.     X        if (InputBufPtr == NULL)  /* EOF */
  244.     X            Abort("Invalid input format");
  245.     X        if (EndOfAllPages(InputBufPtr)) {
  246.     X            /* Put a page delimeter into the end of this page so
  247.     X               we can find the end when we are printing everything
  248.     X               out */
  249.     X            *InputBufPtr = 'p';
  250.     X            break;
  251.     X        }
  252.     X        CharIndex += strlen(InputBufPtr) + 1;
  253.     X        /* +1 so we don't write over the null terminator */
  254.     X        if (CharIndex >= PAGEBUFSIZE) {
  255.     X            Abort("Page size being malloc'd is too small (recompile with larger PAGEBUFSIZE)");
  256.     X        }
  257.     X        if (PageDelim(*InputBufPtr)) {
  258.     X#ifdef REALLOC
  259.     X            /* Now that we know how big this page is, realloc the
  260.     X               old page buffer so we don't waste unused space */
  261.     X            PageBuf[PageIndex] = realloc(PageBuf[PageIndex],
  262.     X                             CharIndex);
  263.     X            if (PageBuf[PageIndex] == NULL)
  264.     X                Abort("realloc returned no storage");
  265.     X#endif REALLOC
  266.     X            /* (Leave the page delimeter in place so we can find
  267.     X               the end of the old page when we are printing
  268.     X               everything out).  Advance PageIndex, reset
  269.     X               CharIndex, and malloc more storage, so we can start
  270.     X               reading in the next page */
  271.     X            PageIndex++;
  272.     X            PageBuf[PageIndex] = malloc(PAGEBUFSIZE);
  273.     X            if (PageBuf[PageIndex] == NULL)
  274.     X                Abort("malloc returned no storage");
  275.     X            CharIndex = 0;
  276.     X        }
  277.     X    } while(1);
  278.     X
  279.     X
  280.     X    /* Now print out the buffered up pages in reverse order */
  281.     X
  282.     X    for (PageIndex = PageIndex; PageIndex >= 0; PageIndex--) {
  283.     X        CharIndex = 0;
  284.     X        /* Output the page delimeter record expected by the drivers */
  285.     X        printf("p%d\n", PageIndex + 1);
  286.     X        do {
  287.     X            if (PageDelim(PageBuf[PageIndex][CharIndex]))
  288.     X                break;
  289.     X            fputs(&PageBuf[PageIndex][CharIndex], stdout);
  290.     X            CharIndex += strlen(&PageBuf[PageIndex][CharIndex]) + 1;
  291.     X            /* +1 to skip the null terminator */
  292.     X        } while(1);
  293.     X    }
  294.     X
  295.     X    /* Now print out the final lines, starting with the end-pages
  296.     X       delimeter line */
  297.     X    puts(EndOfAllPagesDelimString);
  298.     X    PageIndex = 0;
  299.     X    CharIndex = 0;
  300.     X#ifdef REALLOC
  301.     X    /* Current PageBuf may have been chopped off too short for final
  302.     X       stuff */
  303.     X    PageBuf[PageIndex] = realloc(PageBuf[PageIndex], PAGEBUFSIZE);
  304.     X    if (PageBuf[PageIndex] == NULL)
  305.     X        Abort("realloc returned no storage");
  306.     X#endif REALLOC
  307.     X    do {
  308.     X        InputBufPtr = fgets(&PageBuf[PageIndex][CharIndex],
  309.     X                    PAGEBUFSIZE, InputFile);
  310.     X        if (InputBufPtr == NULL)   /* EOF */
  311.     X            exit(0);
  312.     X        fputs(InputBufPtr, stdout);
  313.     X    } while(1);
  314.     X}
  315.     X
  316.     XAbort(Message)
  317.     Xchar *Message;
  318.     X{
  319.     X        fprintf(stderr, "ditrev: %s at page %d\n", Message, PageIndex);
  320.     X        exit(1);
  321.     X}
  322. SHAR_EOF
  323. if test 5198 -ne "`wc -c < 'ditrev.c'`"
  324. then
  325.     echo shar: "error transmitting 'ditrev.c'" '(should have been 5198 characters)'
  326. fi
  327. fi
  328. echo shar: "extracting 'makefile'" '(146 characters)'
  329. if test -f 'makefile'
  330. then
  331.     echo shar: "will not over-write existing file 'makefile'"
  332. else
  333. sed 's/^    X//' << \SHAR_EOF > 'makefile'
  334.     X# use -DREALLOC if you want this program to use realloc(1)
  335.     XCFLAGS = -O -DREALLOC
  336.     X
  337.     Xditrev:    ditrev.c
  338.     X    cc ${CFLAGS} -o ditrev ditrev.c
  339.     X    strip ditrev
  340. SHAR_EOF
  341. if test 146 -ne "`wc -c < 'makefile'`"
  342. then
  343.     echo shar: "error transmitting 'makefile'" '(should have been 146 characters)'
  344. fi
  345. fi
  346. exit 0
  347. #    End of shell archive
  348.